package naito_rescue.agent;

import java.util.*;
import java.io.*;
import rescuecore2.worldmodel.*;
import rescuecore2.messages.Command;
import rescuecore2.misc.Pair;
import rescuecore2.misc.geometry.*;
import rescuecore2.log.Logger;
import rescuecore2.standard.entities.*;
import rescuecore2.standard.messages.*;

import naito_rescue.*;
import naito_rescue.agent.*;
import naito_rescue.object.*;
import naito_rescue.router.*;
import naito_rescue.task.*;
import naito_rescue.task.job.*;
import naito_rescue.util.sort.*;
import naito_rescue.util.fb.*;
import naito_rescue.message.*;
import naito_rescue.message.manager.*;
import static naito_rescue.debug.DebugUtil.*;

/* Task-Jobを基にした行動設計 */
public class NAITOFireBrigade extends NAITOEnvironmentAgent<FireBrigade>
{
	boolean debug = true;
	
	private ArrayList<Building> burningHearBuildings;
	private Random  seed;
	private List<EntityID> savedPath = null;
	private StandardEntity previousLocation = null;
	private int     sameLocationCount = 0;
	
    protected void postConnect() {
        super.postConnect();
        model.indexClass(StandardEntityURN.BUILDING, StandardEntityURN.REFUGE);

		seed = new Random();
		if(!this.crowlingBuildings.isEmpty()){
			//logger.info("crowlingBuildings shuffled. ", "FB#postConnect");
			Collections.shuffle(this.crowlingBuildings, seed);
		}
	}

	public String toString(){
		return "NAITOFireBrigade." + me().getID() + "";
	}

	protected void think(int time, ChangeSet changed, Collection<Command> heard){
		String context = "FB#think";
		super.think(time, changed, heard);
		
		if (time < config.getIntValue(kernel.KernelConstants.IGNORE_AGENT_COMMANDS_KEY)){
			return;
		}else if(time == config.getIntValue(kernel.KernelConstants.IGNORE_AGENT_COMMANDS_KEY)){
		}
		
		/* フィルタリングされたFireMessageから，消火する建物を決定する */
		addTaskByMessage(filteredMessages); // フィルタリングされたFireMessageから，建物を消火するタスクを追加する
		if(!currentTaskList.isEmpty()){
			// 建物消火のタスクがあるならば，移動 -> 消火 を実行する
			//logger.info("currentTaskList = " + currentTaskList, context);
			currentTask  = currentTaskList.peek(); //優先度の最も高いタスクを取得(燃えている and 最も近い建物ほど優先度が高い)
			if(currentTask != null){
				currentJob = currentTask.currentJob();
				if(currentJob != null){
					currentJob.act();
					return;
				}
			}
		}
		// 自分の身の回りに燃えている建物があれば消火する
		if(extinguishAroundHere()){
			return;
		}
		doDefaultSearch();
	}
	protected boolean extinguishAroundHere(){
		List<Building> aroundHeres = new ArrayList<Building>();
		List<Building> farAroundHeres = new ArrayList<Building>();
		for(EntityID visibleID : this.changed.getChangedEntities()){
			if(model.getEntity(visibleID) instanceof Building){
				Building b = (Building)(model.getEntity(visibleID));
				int distance = model.getDistance(getLocation(), b);
				if(distance < this.maxExtinguishDistance){
					if(b.isOnFire()){
						aroundHeres.add(b);
					}else{
						//preExtinguish
						double temp = FireBrigadeUtils.ignitionLevel(getConfig(),b);
						if(b.isTemperatureDefined() && b.getTemperature() > temp){
							aroundHeres.add(b);
						}
					}
				}else{
					farAroundHeres.add(b);
				}
			}
		}
		if(!aroundHeres.isEmpty()){
			//logger.info("Shoud extinguish around here. ", "NAITOFireBrigade#extinguishAroundHere");
			//優先度の降順にソートする
			Collections.sort(aroundHeres, ComparatorUtils.getBuildingPriorityComparator(this));
			Building target = aroundHeres.get(0);
			extinguish(target);
			return true;
		}
		if(!farAroundHeres.isEmpty()){
			Collections.sort(farAroundHeres, new DistanceSorter(getLocation(), model));
			Building target = farAroundHeres.get(0);
			List<EntityID> path = search.backwardAStarSearch(target.getID());
			if(path != null){
				move(path);
				return true;
			}
		}
		return false;
	}
	/*
	protected void addTaskInExtinguishableRange(){
		//logger.info("** addTaskInExtinguishableRange; **");
		for(StandardEntity b : allBuildings){
			Building building = (Building)b;
			
			int distance = model.getDistance(getLocation(), building);
			if(building.isOnFire()){
				//currentTaskList.add(new ExtinguishTask(this, building));
				addTaskIfNew(new ExtinguishTask(this, building));
				//logger.info("Add ExtinguishTask In Range.:" + building);
			}
		}
		//logger.info("** addTaskInExtinguishableRange; end **");
	}
	*/
	protected void removeFinishedTask(){
		//logger.info("** removeFinishedTask(); **");
		for(Iterator<Task> it = currentTaskList.iterator();it.hasNext();){
			Task t = it.next();
			if(t.isFinished()){
				//logger.info("Remove finished task: " + t);
				it.remove();
			}
		}
		//logger.info("** removeFinishedTask(); end **");
	}
	protected void addTaskByMessage(List<NAITOMessage> receivedNow){
		//logger.info("** addTaskByMessage(); **");
		for(NAITOMessage m : receivedNow){
			if(m instanceof FireMessage){
				FireMessage fm = (FireMessage)m;
				List<EntityID> ids = fm.getIDs();
				for(EntityID id : ids){
					Building target = (Building)(model.getEntity(id));
					//currentTaskList.add(new ExtinguishTask(this, target));
					addTaskIfNew(new ExtinguishTask(this, target));
					//logger.info("Add ExtinguishTask By Message.:" + target, "addTaskByMessage");
				}
			}
		}
		//logger.info("** addTaskByMessage(); end **");
	}
	protected void updateTaskPriority(){
		Object[] tasks = currentTaskList.toArray();
		currentTaskList.clear();
		for(Object t : tasks){
			Task task = (Task)t;
			task.updatePriority();
			currentTaskList.add(task);
		}
	}
	protected EnumSet<StandardEntityURN> getRequestedEntityURNsEnum(){
		return EnumSet.of(StandardEntityURN.FIRE_BRIGADE);
	}

}
